package com.straw.hat.com.straw.hat.jdk.concurrent.aqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * AQS的作用就是实现多线程之间同步的,原理的概念 park+自旋
 * @company: 鲸灵科技
 * @author: qiyue@webuy.ai
 * @date: 2019/9/29
 * @time: 11:26 下午
 */
public class AqsNonfairLockStudy extends AbstractQueuedSynchronizer implements Lock {



    @Override
    public void lock() {
        /*先检查state有没有被获取*/
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
        } else {

/*
                < if (!tryAcquire(arg) &&
                    acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                    selfInterrupt();
                >
              1.该方法会调用到tryAcquire(就是我们重写的方法)
                <
              2.等待队列(FIFO)的构建addWaiter
                private Node addWaiter(Node mode) {
                    Node node = new Node(Thread.currentThread(), mode);
                    Node pred = tail;
                    //当前结点设置到尾巴结点
                    if (pred != null) {
                        node.prev = pred;
                        if (compareAndSetTail(pred, node)) {
                            pred.next = node;
                            return node;
                        }
                    }
                    //初始化头结点和尾节点
                    enq(node);
                    return node;
                >
                <
                private Node enq(final Node node) {
                    for (;;) {
                        Node t = tail;
                        if (t == null) { // Must initialize
                            if (compareAndSetHead(new Node()))
                                tail = head;
                        } else {
                            node.prev = t;
                            if (compareAndSetTail(t, node)) {
                                t.next = node;
                                return t;
                            }
                        }
                    }
                }
                >
              3.tryAcquire失败尝试加入wait队列(在AQS中实现--设置Node节点)
              <
              final boolean acquireQueued(final Node node, int arg) {
                    boolean failed = true;
                    try {
                        boolean interrupted = false;
                        //自旋等待
                        for (;;) {
                            final Node p = node.predecessor();
                            if (p == head && tryAcquire(arg)) {
                                //1.如果自己的前置结点是头结点 / 2.尝试获取到锁之后将自己设置为头结点
                                setHead(node);
                                p.next = null; // help GC
                                failed = false;
                                return interrupted;
                            }
                            if (shouldParkAfterFailedAcquire(p, node) &&
                                parkAndCheckInterrupt())
                                interrupted = true;
                        }
                    } finally {
                        if (failed)
                            cancelAcquire(node);
                    }
                }
              >
              <
                  //靠找到一个前驱结点为SIGNAL来决定自己的阻塞
                  private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
                    int ws = pred.waitStatus;
                    if (ws == Node.SIGNAL)
                        return true;
                    if (ws > 0) {
                        do {
                            node.prev = pred = pred.prev;
                        } while (pred.waitStatus > 0);
                        pred.next = node;
                    } else {
                        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
                    }
                    return false;
                  }
              >
              3.acquireQueued
*/
            acquire(1);
        }
    }

    @Override
    protected boolean tryAcquire(int arg) {
        int c = getState();
        /*尝试获取锁*/
        Thread exclusiveOwnerThread = getExclusiveOwnerThread();
        if (c == 0 && compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
            /*判断是不是当前线程*/
        } else if (c != 0 && exclusiveOwnerThread.equals(Thread.currentThread())){
            Integer nxtState = c + arg;
            if (nxtState < 0) {
                /*超出Integer限制*/
                throw new Error("Maximum lock count exceeded");
            }
            setState(nxtState);
            return true;
        }
        return false;
    }



    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    @Override
    public void unlock() {

    }

    @Override
    public Condition newCondition() {
        return null;
    }
}
